package org.jeecg.modules.demo.util;

import io.netty.handler.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @ClassName BitUtil
 * @Description 进制转换工具类
 * @Author @zzh
 * @Date 2023/5/4 09:18
 * @Version 1.0
 */
public class BitUtil {

    /**
     * @Author @zzh
     * @Description // 将普通字符串转换为16进制字符串
     * @Date 09:41 2023/5/4
     * @param str 普通字符串
     * @param lowerCase 转换后的字母为是否为小写  可不传默认为true
     * @param charset   编码格式  可不传默认为Charset.defaultCharset()
     * @return java.lang.String
     * @throws UnsupportedEncodingException
     **/
    public static String str2HexStr(String str, boolean lowerCase, String charset) throws UnsupportedEncodingException {
        return Hex.encodeHexString(str.getBytes(charset), lowerCase);
    }

    /**
     * @Author @zzh
     * @Description //将16进制字符串转换为普通字符串
     * @Date 09:42 2023/5/4
     * @param hexStr  16进制字符串
     * @param charset 编码格式 可不传默认为Charset.defaultCharset()
     * @return java.lang.String
     * @throws DecoderException
     * @throws UnsupportedEncodingException
     **/
//    public static String hexStr2Str(String hexStr, String charset) throws DecoderException, UnsupportedEncodingException, org.apache.commons.codec.DecoderException {
//        byte[] bytes = Hex.decodeHex(hexStr);
//        return new String(bytes, charset);
//    }

    /**
     * @Author @zzh
     * @Description // 将16进制字符串转换为byte数组
     * @Date 10:22 2023/5/4
     * @param hexItr 16进制字符串
     * @return byte[]
     **/
    public static byte[] hexItr2Arr(String hexItr) throws DecoderException, org.apache.commons.codec.DecoderException {
        return Hex.decodeHex(hexItr);
    }

    /**
     * @Author @zzh
     * @Description // byte数组转化为16进制字符串
     * @Date 10:24 2023/5/4
     * @param arr 数组
     * @param lowerCase 转换后的字母为是否为小写 可不传默认为true
     * @return java.lang.String
     **/
    public static String arr2HexStr(byte[] arr, boolean lowerCase) {
        return Hex.encodeHexString(arr, lowerCase);
    }

    /**
     * @Author @zzh
     * @Description // 将普通字符串转换为指定格式的byte数组
     * @Date 10:33 2023/5/4
     * @param str 普通字符串
     * @param charset 编码格式 可不传默认为Charset.defaultCharset()
     * @return byte[]
     * @throws UnsupportedEncodingException
     **/
    public static byte[] str2Arr(String str,String charset) throws UnsupportedEncodingException {
        return str.getBytes(charset);
    }

    /**
     * @Author @zzh
     * @Description // 将byte数组转换为指定编码格式的普通字符串
     * @Date 10:35 2023/5/4
     * @param arr byte数组
     * @param charset 编码格式 可不传默认为Charset.defaultCharset()
     * @return java.lang.String
     * @throws UnsupportedEncodingException
     **/
    public static String arr2Str(byte[] arr,String charset) throws UnsupportedEncodingException {
        return new String(arr,charset);
    }

    /**
     * @Author @zzh
     * @Description // char进制转换
     * @Date 10:36 2023/5/4
     * @param c
     * @return byte
     **/
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    /**
     * @Author @zzh
     * @Description // byte转化为16进制字符串
     * @Date 10:39 2023/5/4
     * @param mByte 字节
     * @return java.lang.String
     **/
    public static String byteToHexString(byte mByte) {
        char[] Digit = { '0', '1', '2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        char[] arr = new char[2];
        arr[0] = Digit[(mByte>>>4)&0X0F];// ? >>>
        arr[1] = Digit[mByte&0X0F];
        String tmp = new String(arr);
        return tmp;
    }

    /**
     *
     * @Author @zzh
     * @Description // 将16进制转换为二进制byte数组
     * @Date 10:42 2023/5/4
     * @param hexStr
     * @return byte[]
     **/
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    /**
     * @Author @zzh
     * @Description // 16进制bety[]转换String字符串.方法一
     * @Date 10:46 2023/5/4
     * @param data
     * @return java.lang.String 返回字符串无空格
     **/
    public static String bytesToString(byte[] data) {
        char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[data.length * 2];
        for (int j = 0; j < data.length; j++) {
            int v = data[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        String result = new String(hexChars);
        return result;
    }

    /**
     * @Author @zzh
     * @Description // 16进制bety[]转换String字符串.方法二
     * @Date 10:49 2023/5/4
     * @param bytes
     * @return java.lang.String 返回字符串有空格
     **/
    public static String bytesToString2(byte[] bytes) {
        final char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = hexArray[v >>> 4];
            hexChars[i * 2 + 1] = hexArray[v & 0x0F];
            sb.append(hexChars[i * 2]);
            sb.append(hexChars[i * 2 + 1]);
            sb.append(' ');
        }
        return sb.toString();
    }

    /**
     * @Author @zzh
     * @Description // 16进制bety[]转换String字符串.方法三
     * @Date 10:54 2023/5/4
     * @param arg
     * @return java.lang.String 返回字符串有空格
     **/
    public static String bytesToString3(byte[] arg) {
        String result = new String();
        if (arg != null) {
            for (int i = 0; i < arg.length; i++) {
                result = result
                        + (Integer.toHexString(
                        arg[i] < 0 ? arg[i] + 256 : arg[i]).length() == 1 ? "0"
                        + Integer.toHexString(arg[i] < 0 ? arg[i] + 256
                        : arg[i])
                        : Integer.toHexString(arg[i] < 0 ? arg[i] + 256
                        : arg[i])) + " ";
            }
            return result;
        }
        return "";
    }

    /**
     * @Author @zzh
     * @Description // String字符串转换16进制bety[].方法一
     * @Date 10:58 2023/5/4
     * @param s
     * @return byte[]
     **/
    public static byte[] stringToBytes(String s) {
        s = s.replace(" ", "");
        s = s.replace("#", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return baKeyword;
    }

    /**
     * @Author @zzh
     * @Description // String字符串转换16进制bety[].方法二
     * @Date 11:05 2023/5/4
     * @param arg
     * @return byte[]
     **/
    private static byte[] stringToBytes2(String arg) {
        if (arg != null) {
            char[] NewArray = new char[1000];
            char[] array = arg.toCharArray();
            int length = 0;
            for (int i = 0; i < array.length; i++) {
                if (array[i] != ' ') {
                    NewArray[length] = array[i];
                    length++;
                }
            }
            int EvenLength = (length % 2 == 0) ? length : length + 1;
            if (EvenLength != 0) {
                int[] data = new int[EvenLength];
                data[EvenLength - 1] = 0;
                for (int i = 0; i < length; i++) {
                    if (NewArray[i] >= '0' && NewArray[i] <= '9') {
                        data[i] = NewArray[i] - '0';
                    } else if (NewArray[i] >= 'a' && NewArray[i] <= 'f') {
                        data[i] = NewArray[i] - 'a' + 10;
                    } else if (NewArray[i] >= 'A' && NewArray[i] <= 'F') {
                        data[i] = NewArray[i] - 'A' + 10;
                    }
                }
                byte[] byteArray = new byte[EvenLength / 2];
                for (int i = 0; i < EvenLength / 2; i++) {
                    byteArray[i] = (byte) (data[i * 2] * 16 + data[i * 2 + 1]);
                }
                return byteArray;
            }
        }
        return new byte[] {};
    }

    /**
     * @Author @zzh
     * @Description // String字符串转换16进制bety[].方法三
     * @Date 11:16 2023/5/4
     * @param str
     * @return byte[]
     **/
    public static byte[] stringToBytes3(String str) {
        if(str == null || str.trim().equals("")) {
            return new byte[0];
        }
        str = str.replace(" ", "");
        byte[] bytes = new byte[str.length() / 2];
        for(int i = 0; i < str.length() / 2; i++) {
            String subStr = str.substring(i * 2, i * 2 + 2);
            bytes[i] = (byte) Integer.parseInt(subStr, 16);
        }
        return bytes;
    }

    /**
     * @Author @zzh
     * @Description // String字符串转换16进制bety[].方法四
     * @Date 11:27 2023/5/4
     * @param hex
     * @return byte[]
     **/
    public static byte[] stringToBytes4(String hex) {
        hex = hex.replace(" ", "");
        if ((hex == null) || (hex.equals(""))){
            return null;
        }
        else if (hex.length()%2 != 0){
            return null;
        }
        else{
            hex = hex.toUpperCase();
            int len = hex.length()/2;
            byte[] b = new byte[len];
            char[] hc = hex.toCharArray();
            for (int i=0; i<len; i++){
                int p=2*i;
                b[i] = (byte) (charToByte(hc[p]) << 4 | charToByte(hc[p+1]));
            }
            return b;
        }
    }

    /**
     * @Author @zzh
     * @Description // 将16进制字符串转换成汉字
     * @Date 13:58 2023/5/4
     * @param str
     * @return java.lang.String
     **/
    public static String deUnicode(String str) {
        byte[] bytes = new byte[str.length() / 2];
        byte tempByte = 0;
        byte tempHigh = 0;
        byte tempLow = 0;
        for (int i = 0, j = 0; i < str.length(); i += 2, j++) {
            tempByte = (byte) (((int) str.charAt(i)) & 0xff);
            if (tempByte >= 48 && tempByte <= 57) {
                tempHigh = (byte) ((tempByte - 48) << 4);
            } else if (tempByte >= 97 && tempByte <= 101) {
                tempHigh = (byte) ((tempByte - 97 + 10) << 4);
            }
            tempByte = (byte) (((int) str.charAt(i + 1)) & 0xff);
            if (tempByte >= 48 && tempByte <= 57) {
                tempLow = (byte) (tempByte - 48);
            } else if (tempByte >= 97 && tempByte <= 101) {
                tempLow = (byte) (tempByte - 97 + 10);
            }
            bytes[j] = (byte) (tempHigh | tempLow);
        }
        String result = null;
        try {
            result = new String(bytes, "GBK");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @Author @zzh
     * @Description // 16进制直接转换成为字符串(无需Unicode解码)
     * @Date 14:18 2023/5/4
     * @param hexStr
     * @return java.lang.String
     **/
//    public static String hexStr2Str(String hexStr) {
//        String str = "0123456789ABCDEF";
//        char[] hexs = hexStr.toCharArray();
//        byte[] bytes = new byte[hexStr.length() / 2];
//        int n;
//        for (int i = 0; i < bytes.length; i++) {
//            n = str.indexOf(hexs[2 * i]) * 16;
//            n += str.indexOf(hexs[2 * i + 1]);
//            bytes[i] = (byte) (n & 0xff);
//        }
//        return new String(bytes);
//    }

    /**
     *
     * @Author @zzh
     * @Description // 16进制转二进制
     * @Date 14:32 2023/5/4
     * @param hex 16进制字符串
     * @return java.lang.String 二进制字符串
     **/
    public static String fromHexString(String hex) {
        if (StringUtils.isEmpty(hex) || hex.length() % 2 != 0) {
            return "";
        }
        StringBuilder binaryStr = new StringBuilder();
        String temp;
        for (int i = 0; i < hex.length(); i++) {
            temp = "0000" + Integer.toBinaryString(Integer.parseInt(hex.substring(i, i + 1), 16));
            binaryStr.append(temp.substring(temp.length() - 4));
        }
        return binaryStr.toString();
    }

    /**
     * 二进制转16进制
     * @Author @zzh
     * @Description // 二进制转16进制
     * @Date 14:40 2023/5/4
     * @param binary 二进制
     * @return java.lang.String 16进制字符串
     **/
    public static String toHexString(String binary) {
        if (StringUtils.isEmpty(binary) || binary.length() % 8 != 0) {
            return "";
        }
        StringBuilder hex = new StringBuilder();
        int tep;
        for (int i = 0; i < binary.length(); i += 4) {
            tep = 0;
            for (int j = 0; j < 4; j++) {
                tep += Integer.parseInt(binary.substring(i + j, i + j + 1)) << (4 - j - 1);
            }
            hex.append(Integer.toHexString(tep));
        }

        return hex.toString();
    }

    /**
     * 十六进制转10进制 按位计算，位值乘权重
     * @Author @zzh
     * @Description // 十六进制转10进制
     * @Date 14:59 2023/5/4
     * @param hex
     * @return int
     **/
    public static int hexToDecimal(String hex) {
        int outcome = 0;
        for (int i = 0; i < hex.length(); i++) {
            char hexChar = hex.charAt(i);
            outcome = outcome * 16 + charToDecimal(hexChar);
        }
        return outcome;
    }

    /**
     * @Author @zzh
     * @Description // 将字符转化为数字
     * @Date 15:00 2023/5/4
     * @param c
     * @return int
     **/
    public static int charToDecimal(char c){
        if(c >= 'A' && c <= 'F')
            return 10 + c - 'A';
        else
            return c - '0';
    }

    /**
     * @Author @zzh
     * @Description // 十六进制转十进制
     * @Date 17:00 2023/5/4
     * @param content
     * @return int
     **/
    public static int covert(String content) {
        int number = 0;
        String[] HighLetter = {"A", "B", "C", "D", "E", "F"};
        Map<String, Integer> map = new HashMap<>();
        for (int i = 0; i <= 9; i++) {
            map.put(i + "", i);
        }
        for (int j = 10; j < HighLetter.length + 10; j++) {
            map.put(HighLetter[j - 10], j);
        }
        String[] str = new String[content.length()];
        for (int i = 0; i < str.length; i++) {
            str[i] = content.substring(i, i + 1);
        }
        for (int i = 0; i < str.length; i++) {
            number += map.get(str[i]) * Math.pow(16, str.length - 1 - i);
        }
        return number;
    }

    /**
     * 子字符串modelStr在字符串str中第count次出现时的下标
     * @Author @zzh
     * @Description // 子字符串modelStr在字符串str中第count次出现时的下标
     * @Date 17:01 2023/5/4
     * @param str
     * @param modelStr
     * @param count
     * @return int
     **/
    public static int getFromIndex(String str, String modelStr, Integer count) {
        //对子字符串进行匹配
        Matcher slashMatcher = Pattern.compile(modelStr).matcher(str);
        int index = 0;
        //matcher.find();尝试查找与该模式匹配的输入序列的下一个子序列
        while(slashMatcher.find()) {
            index++;
            //当modelStr字符第count次出现的位置
            if(index == count){
                break;
            }
        }
        //matcher.start();返回以前匹配的初始索引。
        return slashMatcher.start();
    }


    /**
     * @Author @zzh
     * @Description // 字节转换二进制数字字符串
     * @Date 17:02 2023/5/4
     * @param b
     * @return java.lang.String
     **/
    public static String getTwobinary(byte b) {
        String result = "";
        byte a = b;
        for (int i = 0; i < 8; i++) {
            byte c = a;
            a = (byte) (a >> 1);//每移一位如同将10进制数除以2并去掉余数。
            a = (byte) (a << 1);
            if (a == c) {
                result = "0" + result;
            } else {
                result = "1" + result;
            }
            a = (byte) (a >> 1);
        }
        return result;
    }

    /**
     * @Author @zzh
     * @Description // byte转为十进制int
     * @Date 16:42 2023/5/4
     * @param bytes
     * @return int
     **/
    public static int byte2int(byte bytes) {
        // 将byte转换为8位二进制字符串 依赖 commons-lang-x.x.jar包
        String binaryString = StringUtils.leftPad(Integer.toBinaryString(bytes & 0xff), 8, '0');
        // 将二进制字符串转换为十进制整数值
        int value = Integer.parseInt(binaryString, 2);
        return value;
    }

}

